package gui;

import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import net.glxn.qrgen.QRCode;
import net.glxn.qrgen.image.ImageType;

public class Util 
{
	public static BufferedImage superResampleSimple(BufferedImage src, int targetW, int targetH)
	{
		return superResample(src, 0, 0, src.getWidth(), src.getHeight(),targetW, targetH, 32, 1.0, 1.0);
	}
	
	public static BufferedImage superResample(BufferedImage src, int srcX0, int srcY0, int srcX1, int srcY1, int dstW, int dstH, int sampleCount, double sRange, double sPower)
	{
		if(src == null) return null;
		
		BufferedImage resImage = new BufferedImage(dstW, dstH, BufferedImage.TYPE_4BYTE_ABGR);
		
		WritableRaster srcRaster = src.getRaster();
		WritableRaster dstRaster = resImage.getRaster();
		
		int srcW = src.getWidth();
		int srcH = src.getHeight();
		
		int[] pix00 = new int[4];
		int[] pix01 = new int[4];
		int[] pix10 = new int[4];
		int[] pix11 = new int[4];
		
		int[] dstPix = new int[4];
		
		double scaleX = (double)(srcX1 - srcX0) / (double)dstW;
		double scaleY = (double)(srcY1 - srcY0) / (double)dstH;
		//double offsetX = srcX0;
		//double offsetY = srcY0;
		
		double originX = srcX0;
		double originY = srcY0;
		
		double vecXx = 1.0;
		double vecXy = 0.0;
		double vecYx = 0.0;
		double vecYy = 1.0;
		
		vecXx *= scaleX;
		vecXy *= scaleX;
		
		vecYx *= scaleY;
		vecYy *= scaleY;
		
		//System.out.println("VecX { " + vecXx + ", " + vecXy + " }");
		//System.out.println("VecY { " + vecYx + ", " + vecYy + " }");
		//System.out.println("Scale X=" + scaleX + "  Y=" + scaleY);
		
		for(int y = 0; y < dstH; ++y)
		{
			for(int x = 0; x < dstW; ++x)
			{
				double sumR = 0, sumG = 0, sumB = 0, sumA = 0;
				for(int i = 0; i < sampleCount; ++i)
				{
					double angle = Math.random() * Math.PI * 2.0;
					double radius = Math.pow(Math.random(), sPower) * sRange;
					
					//double tX = (x * scaleX) + offsetX + Math.cos(angle) * radius * scaleX;
					//double tY = (y * scaleY) + offsetY + Math.sin(angle) * radius * scaleY;
					double tX = originX + x * vecXx + y * vecYx + Math.cos(angle) * radius * scaleX;
					double tY = originY + y * vecYy + x * vecXy + Math.sin(angle) * radius * scaleY;
					
					int px0 = (int)tX;
					int py0 = (int)tY;
					double spanX = tX - px0;
					double spanY = tY - py0;
					int px1 = px0 + 1;
					int py1 = py0 + 1;
					
					if(px0 < 0) px0 = 0;
					if(py0 < 0) py0 = 0;
					if(px1 < 0) px1 = 0;
					if(py1 < 0) py1 = 0;
					
					if(px0 >= srcW) px0 = srcW - 1;
					if(py0 >= srcH) py0 = srcH - 1;
					if(px1 >= srcW) px1 = srcW - 1;
					if(py1 >= srcH) py1 = srcH - 1;
					
					srcRaster.getPixel(px0, py0, pix00);
					srcRaster.getPixel(px1, py0, pix10);
					srcRaster.getPixel(px0, py1, pix01);
					srcRaster.getPixel(px1, py1, pix11);
					
					double upperR = (pix10[0] - pix00[0]) * spanX + pix00[0];
					double upperG = (pix10[1] - pix00[1]) * spanX + pix00[1];
					double upperB = (pix10[2] - pix00[2]) * spanX + pix00[2];
					double upperA = (pix10[3] - pix00[3]) * spanX + pix00[3];
					
					double lowerR = (pix11[0] - pix01[0]) * spanX + pix01[0];
					double lowerG = (pix11[1] - pix01[1]) * spanX + pix01[1];
					double lowerB = (pix11[2] - pix01[2]) * spanX + pix01[2];
					double lowerA = (pix11[3] - pix01[3]) * spanX + pix01[3];
					
					sumR += (lowerR - upperR) * spanY + upperR;
					sumG += (lowerG - upperG) * spanY + upperG;
					sumB += (lowerB - upperB) * spanY + upperB;
					sumA += (lowerA - upperA) * spanY + upperA;
				}
				
				dstPix[0] = (int)((sumR / sampleCount));
				dstPix[1] = (int)((sumG / sampleCount));
				dstPix[2] = (int)((sumB / sampleCount));
				dstPix[3] = (int)((sumA / sampleCount));
				
				//System.out.println("SS[" + x + ", " + y + "] = {" + dstPix[0] + ", " + dstPix[1] + ", " + dstPix[2] + "}");
				
				if(dstPix[0] < 0) dstPix[0] = 0;
				if(dstPix[1] < 0) dstPix[1] = 0;
				if(dstPix[2] < 0) dstPix[2] = 0;
				if(dstPix[3] < 0) dstPix[3] = 0;
				
				if(dstPix[0] > 255) dstPix[0] = 255;
				if(dstPix[1] > 255) dstPix[1] = 255;
				if(dstPix[2] > 255) dstPix[2] = 255;
				if(dstPix[3] > 255) dstPix[3] = 255;
				
				dstRaster.setPixel(x, y, dstPix);
			}
		}
		
		return resImage;
	}
	
	public static BufferedImage generateQR(String text)
	{
		QRCode code = QRCode.from(text);
		ByteArrayOutputStream bos = code.to(ImageType.PNG).stream();
		byte[] imgBytes = bos.toByteArray();
		ByteArrayInputStream bis = new ByteArrayInputStream(imgBytes);
		try
		{
			BufferedImage image = ImageIO.read(bis);
			return image;
		} 
		catch (IOException e)
		{
			return null;
		}
	}
}
